package com.game.modular.game.playerMatch.service;

import com.game.comment.exection.ServiceException;
import com.game.comment.util.Graph;
import com.game.comment.util.Node;
import com.game.modular.game.battle.info.base.PvpPlayerInfo;
import com.game.modular.game.battle.info.base.PvpPlayerInfoServiceImpl;
import com.game.modular.game.match.service.PvpMatchEndServiceImpl;
import com.game.modular.game.playerInfo.domain.Player;
import com.game.modular.game.playerInfo.service.PlayerServiceImpl;
import com.game.modular.game.playerMatch.service.base.PvpCityBaseServiceImpl;
import com.game.modular.gameCore.map.CityGraph;
import com.game.modular.gameCore.map.domain.CoreCity;
import com.game.modular.gameCore.map.domain.CoreCityLink;
import com.game.modular.gameCore.map.service.impl.CoreCityLinkServiceImpl;
import com.game.modular.gameCore.map.service.impl.CoreCityServiceImpl;
import lombok.extern.slf4j.Slf4j;
import com.game.modular.game.playerMatch.domain.PvpCity;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;

/**
 * 城池信息(PvpCity)表服务实现类
 *
 * @author cxy
 * @since 2024-07-22 15:13:38
 */
@Slf4j
@Service
public class PvpCityServiceImpl extends PvpCityBaseServiceImpl {
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private HashOperations<Object, Object, Object> hashOperations;
    @Resource
    private CoreCityServiceImpl coreCityServiceImpl;
    @Resource
    private CoreCityLinkServiceImpl coreCityLinkService;
    @Resource
    private PlayerServiceImpl accountServiceImpl;
    @Resource
    private PvpPlayerInfoServiceImpl pvpPlayerInfoServiceImpl;
    @Resource
    private PvpMatchEndServiceImpl pvpMatchEndService;
    @Resource
    private PlayerMatchServiceImpl playerMatchServiceImpl;
    @Resource
    private PlayerServiceImpl playerServiceImpl;


    public void initPvpPlayerCity(Long uid, PvpCity city) {
        Player userInfo = playerServiceImpl.select(uid);
        CoreCity coreCity = coreCityServiceImpl.getCache(city.getCoreCityId());
        city.setOwnerUid(uid);
        city.setOwnerName(userInfo.getNickname());
        city.setStatus(1);
        city.setReadyArmy(coreCity.getReadyArmyRate());
        savaCache(city);
    }

    public CoreCityLink bfsAllPaths(Integer startCityId, Integer targetCityId) {
        List<CoreCityLink> cityLinks = coreCityLinkService.listCache();
        Graph graph = CityGraph.initGraph(cityLinks);
        Set<Set<Node>> sets = graph.bfsAllPaths(startCityId, targetCityId);
        if (sets.isEmpty()) {
            throw new ServiceException("没有可用路线");
        }

        // 获取路线
        CoreCityLink dto = CoreCityLink.builder()
                .startCityId(startCityId)
                .targetCityId(targetCityId)
                .needTime(0)
                .build();

        List<CoreCityLink> routes = new ArrayList<>();// 路线集合
        sets.forEach(nodes -> {// 路线
            List<CoreCityLink> links = new ArrayList<>();// 路线的节点集合

            CoreCityLink child = new CoreCityLink();// 路线，节点集合

            List<Node> nodeList = new ArrayList<>(nodes);//
            child.setNeedTime(0);
            child.setStartCityId(nodeList.get(0).getA());
            child.setTargetCityId(nodeList.get(nodeList.size() - 1).getB());
            nodeList.stream().map(node -> this.filter(      // 节点
                    node, cityLinks
            )).forEach(filter -> {
                child.setNeedTime(filter.getNeedTime() + child.getNeedTime());
                links.add(filter);
            });
            child.setMapCellLinkList(links);
            routes.add(child);
        });
        dto.setMapCellLinkList(routes);
        return dto;
    }

    public CoreCityLink bfsMinPaths(Integer startCityId, Integer targetCityId) {
        List<CoreCityLink> cityLinks = coreCityLinkService.listCache();
        Graph graph = CityGraph.initGraph(cityLinks);
        List<Node> sets = graph.bfsMinPaths(startCityId, targetCityId);
        if (sets.isEmpty()) {
            throw new ServiceException("没有可用路线");
        }

        // 获取路线
        CoreCityLink dto = CoreCityLink.builder()
                .startCityId(startCityId)
                .targetCityId(targetCityId)
                .needTime(0)
                .build();

        List<CoreCityLink> routes = new ArrayList<>();// 路线集合
        sets.forEach(nodes -> {// 路线
            List<CoreCityLink> links = new ArrayList<>();// 路线的节点集合

            CoreCityLink child = new CoreCityLink();// 路线，节点集合

            List<Node> nodeList = sets;//
            child.setNeedTime(0);
            child.setStartCityId(nodeList.get(0).getA());
            child.setTargetCityId(nodeList.get(nodeList.size() - 1).getB());
            nodeList.stream().map(node -> this.filter(      // 节点
                    node, cityLinks
            )).forEach(filter -> {
                child.setNeedTime(filter.getNeedTime() + child.getNeedTime());
                links.add(filter);
            });
            child.setMapCellLinkList(links);
            routes.add(child);
        });
        dto.setMapCellLinkList(routes);
        return dto;
    }

    public CoreCityLink bfsOwnerPaths(Long startCityId, Long targetCityId, Integer matchId, Long playerId) {
        List<CoreCityLink> ownerCityLinks;
        // 筛选出城池路线 pvpMatch:53:city
        ownerCityLinks = coreCityLinkService.listCache().stream().filter(item -> {
            return hashOperations.entries("pvpMatch:" + matchId + ":city").values(
            ).stream().map(obj -> {
                PvpCity city = (PvpCity) obj;
                return city.getOwnerUid();
            }).filter(item1 ->
                    item1.equals(playerId)
            ).collect(Collectors.toList()).contains(item.getStartCityId());
        }).collect(Collectors.toList());


        Graph graph = CityGraph.initGraph(ownerCityLinks);
        Set<Set<Node>> sets = graph.bfsAllPaths(Math.toIntExact(startCityId), Math.toIntExact(targetCityId));
        if (sets.isEmpty()) {
            throw new ServiceException("没有可用路线");
        }


        // 获取路线
        CoreCityLink dto = CoreCityLink.builder()
                .startCityId(Math.toIntExact(startCityId))
                .targetCityId(Math.toIntExact(targetCityId))
                .needTime(0)
                .build();

        List<CoreCityLink> routes = new ArrayList<>();// 路线集合
        sets.forEach(nodes -> {// 路线
            List<CoreCityLink> links = new ArrayList<>();// 路线的节点集合

            CoreCityLink child = new CoreCityLink();// 路线，节点集合

            List<Node> nodeList = new ArrayList<>(nodes);//
            child.setNeedTime(0);
            child.setStartCityId(nodeList.get(0).getA());
            child.setTargetCityId(nodeList.get(nodeList.size() - 1).getB());
            nodeList.stream().map(node -> this.filter(      // 节点
                    node, ownerCityLinks
            )).forEach(filter -> {
                child.setNeedTime(filter.getNeedTime() + child.getNeedTime());
                links.add(filter);
            });
            child.setMapCellLinkList(links);
            routes.add(child);
        });
        dto.setMapCellLinkList(routes);
        return dto;
    }

    public CoreCityLink bfsOwnerMinPaths(
            Long startCityId,
            Long targetCityId,
            Integer matchId,
            Long playerId
    ) {
        CoreCityLink coreCityLink = bfsOwnerPaths(startCityId, targetCityId, matchId, playerId);
        coreCityLink.getMapCellLinkList().sort(Comparator.comparing(CoreCityLink::getNeedTime));
        return coreCityLink.getMapCellLinkList().get(0);
    }

    public CoreCityLink filter(Node node, List<CoreCityLink> mapCellLinks) {
        CoreCityLink mapCellLinkDto = new CoreCityLink();
        CoreCityLink mapCellLink1 = mapCellLinks.stream().filter(mapCellLink -> {
            return mapCellLink.getStartCityId() == node.getA() && mapCellLink.getTargetCityId() == node.getB();
        }).collect(Collectors.toList()).get(0);
        mapCellLinkDto.setStartCityId(mapCellLink1.getStartCityId());
        mapCellLinkDto.setTargetCityId(mapCellLink1.getTargetCityId());
        mapCellLinkDto.setNeedTime(mapCellLink1.getNeedTime());
        return mapCellLinkDto;
    }


    public Map<String, Object> transport(Long playerId, Integer startCityId, Integer targetCityId, Integer transportReadyArmy) {
        Long currentMatchId = playerMatchServiceImpl.currentMatchId(playerId);
        if (currentMatchId == 0) {
            throw new ServiceException("当前没有对局");
        }

        // 获取城池消息
        String startKey1 = "pvpMatch:" + currentMatchId + ":city";
        String startKey2 = startCityId + "";
        PvpCity startCity = (PvpCity) hashOperations.get(startKey1, startKey2);
        String targetKey1 = "pvpMatch:" + currentMatchId + ":city";
        String targetKey2 = targetCityId + "";
        PvpCity targetCity = (PvpCity) hashOperations.get(targetKey1, targetKey2);
        if (startCity == null) {
            throw new ServiceException("起始城池不存在");
        }
        if (startCity.getReadyArmy() - transportReadyArmy < 0) {
            throw new ServiceException("预备兵不足");
        }
        if (targetCity == null) {
            throw new ServiceException("目标城池不存在");
        }


        HashMap<String, Object> map = new HashMap<>();
        return map;
    }

    private void transportTroops(
            Integer transportReadyArmy,
            PvpCity startCity,
            PvpCity targetCity
    ) {
        Long matchId = startCity.getMatchId();
        Long ownerUid = startCity.getOwnerUid();
        Long startCityCoreId = startCity.getCoreCityId();
        Long targetCityCoreId = targetCity.getCoreCityId();
        startCity.setReadyArmy(startCity.getReadyArmy() - transportReadyArmy);
        targetCity.setReadyArmy(targetCity.getReadyArmy() + transportReadyArmy);

        startCity = update(startCity);
        targetCity = update(targetCity);
        log.info("===========对局{},玩家{}运兵,city({}({}-{})->{}({}+{}))================",
                matchId, ownerUid,
                startCityCoreId, startCity.getReadyArmy() + transportReadyArmy, transportReadyArmy,
                targetCityCoreId, targetCity.getReadyArmy() - transportReadyArmy, transportReadyArmy
        );
    }


    public PvpCity getPlayerCity(Long playerId, Long targetCityId, Long currentMatchId) {

        String cityKey = "pvpMatch:" + currentMatchId + ":city";
        PvpCity pvpCity = (PvpCity) hashOperations.get(cityKey, targetCityId + "");
        if (pvpCity == null) {
            throw new ServiceException("城池不存在");
        }
        if (!Objects.equals(pvpCity.getOwnerUid(), playerId)) {
            throw new ServiceException("城池不属于你");
        }
        return pvpCity;
    }

    /**
     * 玩家占领城池
     *
     * @param winnerPlayerId
     * @param currentMatchId
     * @param city
     */
    public void playerOccupyTheCity(
            Long winnerPlayerId, Long currentMatchId, PvpCity city
    ) {
        Long originalOwnerId = city.getOwnerUid();

        city.clear(coreCityServiceImpl.getCache(city.getCoreCityId()));
        city.setOwnerUid(winnerPlayerId);
        update(city);
        pvpPlayerInfoServiceImpl.reCountCityInfoAfterOccupy(originalOwnerId, city);
    }

    public PvpCity getPvpCity(Long defenseCityId, Long currentMatchId) {
        List<PvpCity> cities = listCache(
                currentMatchId
        ).stream().filter(item ->
                Objects.equals(item.getCoreCityId(), defenseCityId)
        ).collect(Collectors.toList());
        if (cities.isEmpty()) {
            throw new ServiceException("没有找到防守方的城池");
        }
        PvpCity city = cities.get(0);
        return city;
    }

    /**
     * 清除玩家 所有城市|以及刷新玩家信息
     */
    public void clearAllPlayerCities(PvpPlayerInfo pvpPlayerInfo) {
        Set<Long> currentCity = pvpPlayerInfo.getCurrentCity();
        if (!currentCity.isEmpty()) {
            currentCity.stream()
                    .map(coreCityId -> getCache(pvpPlayerInfo.getMatchId(), coreCityId))
                    .forEach(pvpCity -> {
                        pvpCity.clear(coreCityServiceImpl.getCache(pvpCity.getCoreCityId()));
                        savaCache(pvpCity);
                    });
        }

    }


}
